package com.shouke.jmeter.plugin.httpFileUpload.util;


import java.io.InputStream;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.Vector;
import com.shouke.jmeter.plugin.httpFileUpload.sampler.HeaderArgument;

import org.apache.http.HttpEntity;
//import org.apache.httpFileUpload.HttpStatus;
//import org.apache.httpFileUpload.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
//import org.apache.httpFileUpload.entity.ByteArrayEntity;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
//import org.apache.commons.io.IOUtils;

public class HttpUtil {
    private static PoolingHttpClientConnectionManager connManager = null;
    private static RequestConfig requestConfig = null;
    private static CloseableHttpClient httpClient = null;
    /**
     * 获取连接管理器
     */
    public static PoolingHttpClientConnectionManager getConnManager(String sslTsl, Integer maxConnNum, Integer maxConnPerRoute) throws Exception {
        if (connManager != null) {
            // 1 添加https支持
            SSLContext sslContext = SSLContext.getInstance(sslTsl);

            // 实现一个X509TrustManager接口，用于绕过验证
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
                }

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };

            sslContext.init(null, new TrustManager[]{trustManager}, null); // 初始化此上下文

            // 设置处理http和https 协议的socket链接工厂对象
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE))
                    .build();

            // 2 创建PoolingHttpClientConnectionManager连接管理器，以便HttpClient支持多线程
            connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            connManager.setMaxTotal(maxConnNum); // 设置最大连接数
            connManager.setDefaultMaxPerRoute(maxConnPerRoute); // 设置每个路由的最大连接数
        }
        return connManager;
    }

    /**
     * 获取HTTP请求配置
     */
    public static RequestConfig getRequestConfig(Integer getConnTimeout, Integer connectServerTimeout, Integer waitServerResponseTimeout) throws Exception {
        if (requestConfig != null) {
            // 3 设置默认请求配置
            RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(getConnTimeout) // 设置从连接池中获取连接的超时时间 60秒
                    .setConnectTimeout(connectServerTimeout) // 设置连接服务器超时时间
                    .setSocketTimeout(waitServerResponseTimeout) // 设置等待服务器返回数据超时时间
                    .build();

        }
        return requestConfig;
    }

    /**
     * 获取HTTP请求客户端
     */
    public static CloseableHttpClient getHttpClient(String sslTsl, Integer maxConnNum, Integer maxConnPerRoute,
                                                    Integer getConnTimeout, Integer connectServerTimeout, Integer waitServerResponseTimeout) throws Exception {
        if (httpClient == null) {
            // 1 添加https支持
            SSLContext sslContext = SSLContext.getInstance(sslTsl);

            // 实现一个X509TrustManager接口，用于绕过验证
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
                }

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };

            sslContext.init(null, new TrustManager[]{trustManager}, null); // 初始化此上下文

            // 设置处理http和https 协议的socket链接工厂对象
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE))
                    .build();

            // 2 创建PoolingHttpClientConnectionManager连接管理器，以便HttpClient支持多线程
            PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            connManager.setMaxTotal(maxConnNum); // 设置最大连接数
            connManager.setDefaultMaxPerRoute(maxConnPerRoute); // 设置每个路由的最大连接数


            // 3 设置默认请求配置
            RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(getConnTimeout) // 设置从连接池中获取连接的超时时间 60秒
                    .setConnectTimeout(connectServerTimeout) // 设置连接服务器超时时间
                    .setSocketTimeout(waitServerResponseTimeout) // 设置等待服务器返回数据超时时间
                    .build();


            // 4 创建自定义的httpclient对象
            httpClient = HttpClients.custom().setConnectionManager(connManager)
                    .setDefaultRequestConfig(requestConfig)
                    .build();

        }
        return httpClient;
    }

    /**
     * post请求（用于请求二进制文件上传接口）
     */
    public static String uploadBinaryFile(CloseableHttpClient httpClient, String url, Vector<HeaderArgument> headers, InputStream body,
                                          String responseEncoding) throws Exception {

        // 创建httpPost
        HttpPost httpPost = new HttpPost(url);

        // 设置请求头
        for(HeaderArgument header : headers) { // 循环遍历参数对象，获取请求头名称和值
            httpPost.setHeader(header.getHeaderName(), header.getHeaderValue());
        }


        // 设置实体内容(请求body)
//        byte[] data = IOUtils.toByteArray(instream); // IOUtils.toByteArray(in) 读取输入流内容的字节到字节数组
//        httpPost.setEntity(new ByteArrayEntity(data)); // 设置二进制数组实体

        // 等价实现
        httpPost.setEntity(new InputStreamEntity(body));

        CloseableHttpResponse response = null; // 存放返回结果
        String finalResult = "";
        try {
            // 发送请求

            response = httpClient.execute(httpPost);

            // 6 获取响应
//            StatusLine statusLine = response.getStatusLine(); // 获取响应状态行
//            int statusCode = statusLine.getStatusCode();      // 获取响应状态码，比如 200、201
            HttpEntity responseEntity = response.getEntity(); // 获取响应体
//            if (statusCode == HttpStatus.SC_OK||statusCode == 201) {
//                if (null !=responseEntity) {
//                    finalResult = EntityUtils.toString(responseEntity);
//                    System.out.println(finalResult);
//                }
//            } else { // 请求失败
//                System.out.println("请求出错，状态码:" + statusCode);
//                finalResult = "请求出错，状态码:" + statusCode + "," + responseEntity.toString();
//            }

            if (null != responseEntity) {
                finalResult = EntityUtils.toString(responseEntity, responseEncoding);
            } else {
                finalResult = "请求出错：服务器返回null";
            }
            EntityUtils.consume(responseEntity);
        } catch (Exception e) {
            finalResult = "请求出错：" + e.toString();
        } finally {
            // 释放资源
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    finalResult = finalResult + " response.close()调用出错：" + e.toString();
                }
            }

//            try {
//                httpClient.close();
//            } catch (IOException e){
//                e.printStackTrace();
//                finalResult = finalResult + " httpClient.close()调用出错：" + e.toString();
//            }

        }
        return finalResult;
    }
}
